package main

import (
	"fmt"
	"go-chat/utils"
	"io"
	"net"
	"sync"
	"time"
)

type Server struct {
	Ip   string
	Port int

	OnlineMap     map[string]*User // 在线用户的列表
	OnlineMapLock sync.RWMutex     // 读写锁，读共享，写独占，保护 OnlineMap 的并发访问

	Message chan string // 消息广播的 channel
}

// NewServer 创建并返回一个新的 Server 实例。
func NewServer(ip string, port int) *Server {
	server := &Server{
		Ip:        ip,
		Port:      port,
		OnlineMap: make(map[string]*User),
		Message:   make(chan string),
	}
	return server
}

// HandleClient 处理与客户端的连接，可以在这里实现具体的业务逻辑。
func (server *Server) HandleClient(conn net.Conn) {
	defer conn.Close()
	fmt.Println("新客户端连接：", conn.RemoteAddr())

	user := NewUser(conn, server)
	user.Online()

	// 监听用户是否活跃的 channel
	isAlive := make(chan bool)

	// 处理客户端发送的消息
	go func() {
		buf := make([]byte, utils.MaxBuffSize)
		for {
			bytes, err := conn.Read(buf)
			if bytes == 0 {
				user.Offline()
				return
			}

			if err != nil && err != io.EOF {
				fmt.Println("Conn Read Error:", err)
				return
			}

			// 提取用户的消息（去除'\n'）
			msg := string(buf[:bytes-1])

			// 用户针对msg进行消息处理
			user.DoMessage(msg)

			// 用户发送的任意消息，代表当前用户是活跃的
			isAlive <- true
		}
	}()

	for {
		select {
		case <-isAlive:
			// 当前用户是活跃的，应该重置定时器
			// 不做任何事情，为了激活select，更新下面的定时器
		case <-time.After(utils.TimeoutDuration):
			// 已经超时
			user.SendMsg("已超时")

			// 销毁资源
			close(user.Chan)
			conn.Close()

			fmt.Println(conn.RemoteAddr(), "已超时")
			return
		}
	}
}

// Start 启动服务器，监听指定的 IP 地址和端口号。
func (server *Server) Start() {
	fmt.Println("服务器已启动.")

	// 监听 TCP 连接
	listener, err := net.Listen("tcp", fmt.Sprintf("%s:%d", server.Ip, server.Port))
	if err != nil {
		fmt.Println("监听失败", err)
		return
	}

	// 确保在函数结束时关闭监听器
	defer listener.Close()

	// 启动消息监听 goroutine
	go server.ListenMessager()

	for {
		// 接受客户端的连接请求
		conn, err := listener.Accept()
		if err != nil {
			fmt.Println("接受连接失败", err)
			continue
		}

		// 为每个连接启动一个 goroutine 来处理业务
		go server.HandleClient(conn)
	}
}

// ListenMessager 监听消息 channel，并发送消息给所有在线用户。
func (server *Server) ListenMessager() {
	for {
		msg := <-server.Message

		// 将 msg 发送给全部的在线 User
		server.OnlineMapLock.Lock()
		for _, cli := range server.OnlineMap {
			cli.Chan <- msg
		}
		server.OnlineMapLock.Unlock()
	}
}

// BroadCast 向所有用户广播消息。
func (server *Server) BroadCast(user *User, msg string) {
	sendMsg := "[" + user.Addr + "]" + user.Name + ":" + msg
	server.Message <- sendMsg
}
